//
//  OPTopic.m
//  OPFramework
//
//  Created by malcom on 7/12/08.
//  Copyright 2008 __MyCompanyName__. All rights reserved.
//

#import "OPTopic.h"
#import "OPForum.h"
#import "OPBoard.h"
#import "OPPost.h"
#import "OPBoard_Extensions.h"

@implementation OPTopic

@synthesize obj_parentForum;
@synthesize p_topicID;
@synthesize p_topicPassword;
@synthesize p_topicTitle;
@synthesize p_topicViews;
@synthesize p_creationDate;
@synthesize p_topicReplies;
@synthesize p_topicStatus;
@synthesize p_lastViewDate;
@synthesize p_lastPostDate;
@synthesize _firstPostID;
@synthesize _lastPostID;
@synthesize p_postAuthor;
@synthesize p_lastPoster;
@synthesize obj_postsPages;
@synthesize p_bookmarked;
@synthesize p_firstNewPageSinceLastVisit;
@synthesize p_firstNewPostIDSinceLastVisit;

- (id) _initLinkedToForum:(OPForum *) _forum {
	self = [super initWithBoard: _forum._delegateBoard];
	if (self != nil) {
		obj_parentForum = [_forum retain];
		p_topicPassword = [[NSString alloc] init];
	}
	return self;
}

- (id) initWithTopicID:(NSNumber *) _topicID fromForum:(OPForum *) _forum {
	self = [self _initLinkedToForum: _forum];
	if (self != nil) {
		p_topicID = [[NSNumber alloc] initWithInt: [_topicID intValue]];
	}
	return self;
}

- (id) initLoadingPage:(NSNumber *) _pageIdx ofTopic:(NSNumber *) _topicid fromForum:(OPForum *) _forum password:(NSString *) _password forceLoad:(BOOL) _force {
	if (!_force) 
		self = [_forum getCachedTopicWithID: _topicid];
	
	if (self == nil || _force) {
		self = [self initLoadingTopicWithID: _topicid fromForum: _forum password: _password forceLoad: NO];
		if (self != nil) {
			// what page contains that topic?
			if ([_pageIdx intValue] > -1)
				[obj_postsPages addPage: [self _loadPostsInPage: _pageIdx forceSyncMode: YES] atIndex: _pageIdx];
		}
	}
	return self;
}

- (id) initLoadingPageWithPost:(NSNumber *) _postid ofTopic:(NSNumber *) _topicid fromForum:(OPForum *) _forum password:(NSString *) _password {
	self = [self initLoadingTopicWithID: _topicid fromForum: _forum password: _password forceLoad: NO];
	if (self != nil) {
		// what page contains that topic?
		NSNumber *pageWithTopic = [NSNumber numberWithInt: [_delegateBoard getPostPageIdxOf: _postid inTopic: _topicid ofForum: [NSNumber numberWithInt: _forum._forumID]]];
		if ([pageWithTopic intValue] > -1)
			[obj_postsPages addPage: [self _loadPostsInPage: pageWithTopic forceSyncMode: YES] atIndex: pageWithTopic];
	}
	return self;
}

- (void) refreshData {
	// reset cache
	[obj_postsPages release]; obj_postsPages = [[OPPageContainer alloc] init];
	NSArray *_param = [self _getParamsListForTopicInfo];
	[self sendXMLRequestForMethod: @"msgs.getTopicWithID" withParams: _param parseSelector: @selector(_parseTopicDataRefresh:)];
}

- (NSArray *) _getParamsListForTopicInfo {
	return [NSArray arrayWithObjects: [NSNumber numberWithInt: obj_parentForum._forumID],
						p_topicID, 
						(p_topicPassword == nil ? @"" : p_topicPassword),
						[NSNumber numberWithInt: [_delegateBoard.obj_authUser.user_loginDate timeIntervalSince1970]],
						[_delegateBoard.obj_boardConfig getPropertyForKey: OPBoardConfig_PostsPerPage],nil];
	
}
	
- (void) _parseTopicDataRefresh:(NSArray *) _result {
	NSArray *list = [[_result objectAtIndex: 0] objectForKey: @"topics"];
	[self _loadWithData: [list lastObject]];
}

- (id) initLoadingTopicWithID:(NSNumber *) _topicid fromForum:(OPForum *) _forum password:(NSString *) _password forceLoad:(BOOL) _force {
	if (!_force) 
		self = [_forum getCachedTopicWithID: _topicid];
	
	if (self == nil || _force) {
		self = [super initWithBoard: _forum._delegateBoard];
		if (self != nil) {
			_delegateBoard = [_forum._delegateBoard retain];
			obj_parentForum = [_forum retain];
			p_topicPassword = [[NSString alloc] init];
			
			// perform server request
			BOOL ok = [self sendXMLRequestForMethod: @"msgs.getTopicWithID" withParams:[self _getParamsListForTopicInfo] parseSelector: @selector(_parseTopicDataRefresh:) forceSyncRequest: YES];
			if (!ok) return nil; // something wrong
		}
	}
	return self;
}



- (id) _initWithDataResponse:(NSDictionary *) _data ofForum:(OPForum *) _forum {
	self = [super initWithBoard: _forum._delegateBoard];
	if (self != nil) {
		obj_parentForum = [_forum retain]; // store parent forum
		
		// alloc pages
		obj_postsPages = [[OPPageContainer alloc] init];
		
		p_topicPassword = [[NSString alloc] init];
		
		// load data
		[self _loadWithData: _data];
	}
	return self;
}

- (void) dealloc {
	[obj_parentForum release];
	[p_topicID release];
	[p_topicPassword release];
	[p_topicTitle release];
	[p_topicViews release];
	[p_creationDate release];
	[p_topicReplies release];
	[p_topicStatus release];
	[p_lastViewDate release];
	[p_lastPostDate release];
	[super dealloc];
}


- (NSString *) description {
	return [NSString stringWithFormat: @"OPTopic: %@ by %@ (%d messages) (%d total pages - %d cached - %d real elements) bookmarked: %d",
				p_topicTitle,p_postAuthor.p_username,
				[p_topicReplies intValue]+1,
				obj_postsPages.p_totalPages,
				[obj_postsPages.p_pagesContainer count],
				obj_postsPages.p_totalElements,
				[p_bookmarked intValue]];
}

- (void) _loadWithData:(NSDictionary *) _data {
	obj_postsPages.p_totalElements = [[_data objectForKey: _OPTopic_TopicReplies] intValue];
	obj_postsPages.p_totalPages = ceil( obj_postsPages.p_totalElements / [[_delegateBoard.obj_boardConfig getPropertyForKey: OPBoardConfig_PostsPerPage] intValue])+1;
	
	
	[p_firstNewPageSinceLastVisit release]; p_firstNewPageSinceLastVisit = nil;
	p_firstNewPageSinceLastVisit = [[NSNumber alloc] initWithInt: [[_data objectForKey: @"first_new_page"] intValue]];
	
	[p_firstNewPostIDSinceLastVisit release]; p_firstNewPostIDSinceLastVisit = nil;
	p_firstNewPostIDSinceLastVisit = [[NSNumber alloc] initWithInt: [[_data objectForKey: @"first_new_postid"] intValue]];
	
	// topic status
	[p_topicReplies release];
	p_topicStatus = [[NSNumber alloc] initWithInt: [[_data objectForKey: _OPTopic_TopicStatus] intValue]];
	
	// first post id
	[_firstPostID release];
	_firstPostID = [[NSNumber alloc] initWithInt: [[_data objectForKey: _OPTopic_TopicFirstPostID] intValue]];
	
	// last post id
	[_lastPostID release];
	_lastPostID = [[NSNumber alloc] initWithInt: [[_data objectForKey: _OPTopic_TopicLastPostID] intValue]];

	// topic replies
	[p_topicReplies release];
	p_topicReplies = [[NSNumber alloc] initWithInt: [[_data objectForKey: _OPTopic_TopicReplies] intValue]];
	
	// topic views
	[p_topicViews release];
	p_topicViews = [[NSNumber alloc] initWithInt: [[_data objectForKey: _OPTopic_TopicViews] intValue]];
	
	// last post date
	[p_lastViewDate release];
	p_lastViewDate = [[NSNumber alloc] initWithInt: [[_data objectForKey: _OPTopic_TopicLastViewTime] intValue]];
	
	// last post date
	[p_lastPostDate release];
	p_lastPostDate = [[NSDate dateWithTimeIntervalSince1970: [[_data objectForKey: _OPTopic_TopicLastPostTime] longLongValue]] retain];
	
	// topic id
	p_topicID = [_data objectForKey: _OPTopic_TopicID];
	
	// creating or linking to a reference of post author
	if (p_postAuthor != nil) [p_postAuthor release];
	p_postAuthor = [[_delegateBoard.obj_membersCache getUserMemberFromID: [_data objectForKey: _OPTopic_TopicPoster] withName:[_data objectForKey: _OPTopic_TopicFirstPosterName]] retain];
	// link last post author of the topic
	if (p_lastPoster != nil) [p_lastPoster release];
	p_lastPoster = [[_delegateBoard.obj_membersCache getUserMemberFromID: [_data objectForKey: _OPTopic_TopicLastPosterID] withName:[_data objectForKey: _OPTopic_TopicLastPosterName]] retain];
	
	[p_bookmarked release];
	p_bookmarked = [[_data objectForKey: @"bookmarked"] retain];
	
	// topic title
	[p_topicTitle release];
	p_topicTitle = [[_data objectForKey: _OPTopic_TopicTitle] retain];
}



- (OPPost *) getLastPost {
	return [self getPostWithID: _lastPostID forceLoad: NO];
}

- (OPPost *) getFirstPost {
	return [self getPostWithID: _firstPostID forceLoad: NO];
}


- (OPPost *) getPostWithID:(NSNumber *) _uid forceLoad:(BOOL) _force {
	int toSearch = [_uid intValue];

	if ([self isCacheExpired]) {
		NSArray *pages = [obj_postsPages.p_pagesContainer allKeys];
		for (NSNumber *cPage in pages) {
			NSArray *pagePosts = [obj_postsPages.p_pagesContainer objectForKey: cPage];
			for (OPPost *cPost in pagePosts) {
				if (cPost.p_postID == toSearch)
					return cPost;
			}
		}
	}
	
	if (_force) {
		// nothing found, try to load data from server
		OPPost *post = [[OPPost alloc] initLoadingPostWithID: _uid fromBoard: _delegateBoard];
		return [post autorelease];
	} else return nil;
}

- (NSArray *) getLastPostsPage {
	return [self getPostsInPage: (obj_postsPages.p_totalPages -1)];
}

- (NSArray *) getPostsInPage:(int) _pgIdx  {
	if (_pgIdx == -1) return nil;
	
	NSNumber *whatPage = [NSNumber numberWithInt: _pgIdx];
	
	// if we want to get a new copy or we have not yet downloaded the page or the cache is expired
	if ([obj_postsPages getPageAtIndex: whatPage] == nil || [self isCacheExpired]) {
		// ... we can perform a new request
		//NSArray *list = [self _loadPostsInPage: whatPage];
		// assign the value only if is synchronous
		//if (list != nil) [obj_postsPages setObject: list forKey: whatPage];
		[obj_postsPages addPage: [self _loadPostsInPage: whatPage forceSyncMode: NO] atIndex: whatPage];
	} else [self dataUpdatedFor: self atMethod: @"msgs.getTopicsMessages"];
	
	return [obj_postsPages getPageAtIndex: whatPage];
}

- (NSArray *) _loadPostsInPage:(NSNumber *) _pageIdx forceSyncMode:(BOOL) _sync {
	NSArray *_params = [[NSArray alloc] initWithObjects:
						[NSNumber numberWithInt: obj_parentForum._forumID],
						p_topicID,
						@"",
						[NSArray array],
						_pageIdx,
						@"",
						[NSNumber numberWithInt: 0],
						@"t",
						@"a",
						[NSNumber numberWithBool: NO],
						@"",
						p_topicPassword,
						[_delegateBoard.obj_boardConfig getPropertyForKey:OPBoardConfig_PostsPerPage],nil ];

	// we will make this request in main loop (synchronous mode)
	if (!_asyncModeActive || _sync) {
		// make the request
		XMLRPCResponse *topicsInPage = [_delegateBoard _executeRequestMethodNamed: @"msgs.getTopicsMessages" 
																   withParams: _params
															   attachAuthData: NO];
		[_params release];
		[self _parseLoadPostsAtPageRequest: [NSArray arrayWithObjects: [topicsInPage responseObject],@"msgs.getTopicsMessages" ,nil]];
	} else {
		// we perform a background request
		[_delegateBoard _executeRequestMethodNamed:@"msgs.getTopicsMessages" 
										withParams:_params 
									attachAuthData: nil 
									 asyncResponse: self];
		[_params release];
		return nil;
	}
	return [obj_postsPages getPageAtIndex: _pageIdx];
}

// async response
- (void)connection: (XMLRPCConnection *)connection didReceiveResponse:(XMLRPCResponse *)response forMethod: (NSString *)method {
	// super class check if it's an error, a numeric response or simply some data to parse
	if (![self _checkErrorInRawResponseFromServer: response forMethod:method]) {
		if ([method isEqualToString: @"msgs.getTopicWithID"]) {
			[self _parseTopicDataRefresh: [NSArray arrayWithObjects: [response responseObject],method,nil]];
		} else {
			// data update to parse
			[self _parseLoadPostsAtPageRequest: [NSArray arrayWithObjects: [response responseObject],method,nil]];
		}
		// we can propagate the result to listeners
		[self dataUpdatedFor: self atMethod:method];	
	}
}

- (BOOL) _isNumericResponseFromServerAnErrorCode:(NSNumber *) _code forMethod:(NSString *) method {
	//switch ([_code intValue]) {
	
	//}
	return NO;
}

- (void) dataUpdatedFor:(OPBaseObject *) _obj atMethod:(NSString *) _method {
	[super dataUpdatedFor: _obj atMethod: _method];
}

- (void) _parseLoadPostsAtPageRequest:(NSArray *) topicsInPage {
	NSDictionary *prop = [(NSDictionary*)[topicsInPage objectAtIndex:0] retain];
		
	int _pageIdx = [[prop objectForKey: _OPTopic_PageShowed] intValue];
	// update some cached information about the topic posts
	obj_postsPages.p_totalPages = [[prop objectForKey: _OPTopic_TopicInfo_TotalPages] intValue];
	obj_postsPages.p_totalElements  = [[[prop objectForKey: _OPTopic_TopicInfo] objectForKey: _OPTopic_TopicInfo_TotalPosts] intValue];
		
	// load the page items
	//NSArray *list = [self _loadPostsInPageFromResponse: [prop objectForKey: _OPTopic_TopicsList]];
	// assign to page
	//[obj_postsPages setObject: list forKey: [NSNumber numberWithInt: _pageIdx]];
	[obj_postsPages addPage: [self _loadPostsInPageFromResponse: [prop objectForKey: _OPTopic_TopicsList]] atIndex: [NSNumber numberWithInt: _pageIdx]];
		
	[prop release];
}

- (NSArray *) _loadPostsInPageFromResponse:(NSArray *) _list {
	NSMutableArray *postsList = [[NSMutableArray alloc] init];
	
	for (NSDictionary *cTopic in _list) {
		// create the post object
		OPPost *post = [[OPPost alloc] _initByLoadingResponsePostObject: cTopic fromTopic:self];
		[postsList addObject: post];
		
		// add the author to the member cache or refresh the cache
	//	[_delegateBoard.obj_membersCache refreshUserCacheWithData: cTopic];
		 
	}
	
	return [postsList autorelease];
}

- (BOOL) toggleSetAsBookmark {
	if (![_delegateBoard.obj_authUser isLogged]) return NO; // if you are logged as anoynmous this is a stupid thing to do
	[self sendXMLRequestForMethod: @"user.toogleBookmarkSetting" withParams: nil parseSelector: @selector(_parseSetBookmark:) forceSyncRequest:YES];
	return YES;
}

- (void) _parseSetBookmark:(NSArray *) _result {
	[p_bookmarked release];
	p_bookmarked = [[_result objectAtIndex: 0] retain];
}

@end
